home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Networking / UDPSample / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  9.6 KB  |  471 lines  |  [TEXT/KAHL]

  1. /**************************************
  2.  *
  3.  *  UDP chat sample
  4.  *  ©1991 Apple Computer, MacDTS
  5.  *
  6.  *    Written by Steve Falkenburg 12/13/91
  7.  *
  8.  *    this sample illustrates how to send and receive MacTCP UDP packets, setting up a simple
  9.  *    connectionless chat program.  Instead of an outstanding read command, an ASR is
  10.  *    used to inform the program there is data to be received.  This sample is written for
  11.  *    Think C 5.0, but can be converted easily to MPW C.
  12.  *
  13.  *************************************/
  14.  
  15.  
  16. #include <MacTCPCommonTypes.h>
  17. #include <AddressXlation.h>
  18. #include <UDPPB.h>
  19. #include <GetMyIPAddr.h>
  20.  
  21. /* consts */
  22.  
  23. #define    kDlgID        128                    // dialog item ids
  24. #define    kSend        1
  25. #define    kQuit        2
  26. #define    kSendData    3
  27. #define    kSendTo        4
  28. #define    kRecvData    5
  29. #define    kOutline    9
  30. #define    kErrDlg        129
  31.  
  32. #define    kInFront    (WindowPtr)-1L
  33.  
  34. #define    kUDPPort    12345
  35. #define    kSenderPort    0
  36. #define    kTimeout    5
  37.  
  38. /* prototypes */
  39.  
  40. void main(void);
  41. void InitStuff(void);
  42. void DoError(OSErr err);
  43. void MainLoop(void);
  44. OSErr DoSendData(DialogPtr theDlg);
  45. OSErr DoRecvData(DialogPtr theDlg);
  46.  
  47. pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr);
  48. OSErr ConvertStringToAddr(char *name,ip_addr *netNum);
  49.  
  50. OSErr NetInitUDP(void);
  51. OSErr NetDoneUDP(void);
  52. OSErr NetSendUDP(StreamPtr sendStream,ip_addr sendAddr,udp_port sendPort,char *sendData);
  53. OSErr NetReadUDP(StreamPtr stream,Ptr data,unsigned short *dataLength);
  54. OSErr CreateUDPStream(udp_port udpPort,StreamPtr *theStream,ProcPtr asr);
  55. OSErr ReleaseUDPStream(StreamPtr theStream);
  56.  
  57. pascal void MyASR(
  58.         StreamPtr udpStream, 
  59.         unsigned short eventCode, 
  60.         Ptr userDataPtr,
  61.         struct ICMPReport *icmpMsg);
  62. void DoASR(StreamPtr udpStream,unsigned short eventCode,struct ICMPReport *icmpMsg);
  63. OSErr GetMyIPAddr(ip_addr *addr);
  64. void NumToIPAddr(ip_addr addr,StringPtr ipStr);
  65.  
  66. pascal void FrameItem(DialogPtr theDlg,short item);
  67.  
  68.         
  69. /* globals */
  70.  
  71. static short gMTCPDrvr;                    // MacTCP Driver refnum
  72. StreamPtr gListenerStream;                // udp listener stream
  73. StreamPtr gSenderStream;                // udp sender stream
  74. Boolean gDataPending;                    // true if data has been received
  75. ip_addr gMyIPAddr;                        // my IP address
  76.  
  77. void main(void)
  78. {
  79.     OSErr err;
  80.     
  81.     InitStuff();
  82.  
  83.     if ((err=NetInitUDP())==noErr)
  84.         MainLoop();
  85.     else
  86.         DoError(err);
  87.         
  88.     err = NetDoneUDP();
  89.     if (err!=noErr)
  90.         DoError(err);
  91.         
  92.     ExitToShell();
  93. }
  94.  
  95.  
  96. /* init the toolbox */
  97.  
  98. void InitStuff(void)
  99. {
  100.     InitGraf(&qd.thePort);
  101.     InitFonts();
  102.     InitWindows();
  103.     InitMenus();
  104.     TEInit();
  105.     InitDialogs(nil);
  106.     FlushEvents(everyEvent,0);
  107.     InitCursor();
  108.     
  109.     gDataPending = false;
  110. }
  111.  
  112.  
  113. /* display an error */
  114.  
  115. void DoError(OSErr err)
  116. {
  117.     Str255 errStr;
  118.     
  119.     NumToString(err,errStr);
  120.     ParamText(errStr,"\p","\p","\p");
  121.     StopAlert(kErrDlg,nil);
  122. }
  123.  
  124.  
  125. /* main loop of execution */
  126.  
  127. void MainLoop(void)
  128. {
  129.     short item;
  130.     DialogPtr theDlg;
  131.     Handle iHndl;
  132.     Rect iRect;
  133.     short iType;
  134.     OSErr err;
  135.     Str255 ipStr;
  136.     
  137.     theDlg = GetNewDialog(kDlgID,nil,kInFront);
  138.     GetDItem(theDlg,kOutline,&iType,&iHndl,&iRect);
  139.     SetDItem(theDlg,kOutline,iType,FrameItem,&iRect);
  140.     GetDItem(theDlg,kSendTo,&iType,&iHndl,&iRect);
  141.     NumToIPAddr(gMyIPAddr,ipStr);
  142.     SetIText(iHndl,ipStr);
  143.     SelIText(theDlg,kSendData,0,32767);
  144.     
  145.     do {
  146.         ModalDialog(nil,&item);
  147.         if (item==kSend) {
  148.             err = DoSendData(theDlg);
  149.             if (err!=noErr)
  150.                 DoError(err);
  151.         }
  152.         if (gDataPending) {
  153.             err = DoRecvData(theDlg);
  154.             gDataPending = false;
  155.             if (err!=noErr)
  156.                 DoError(err);
  157.         }
  158.             
  159.     } while (item!=kQuit);
  160.     
  161.     DisposeDialog(theDlg);
  162. }
  163.  
  164.  
  165. /* called to initiate the sending of the UDP packet */
  166.  
  167. OSErr DoSendData(DialogPtr theDlg)
  168. {
  169.     Handle iHndl;
  170.     Rect iRect;
  171.     short iType;
  172.     char sendTo[256],sendData[256];
  173.     ip_addr sendAddr;
  174.     OSErr err;
  175.     
  176.     GetDItem(theDlg,kSendTo,&iType,&iHndl,&iRect);
  177.     GetIText(iHndl,(StringPtr)sendTo);
  178.     GetDItem(theDlg,kSendData,&iType,&iHndl,&iRect);
  179.     GetIText(iHndl,(StringPtr)sendData);
  180.     PtoCstr(sendTo);
  181.     PtoCstr(sendData);
  182.     
  183.     err = ConvertStringToAddr(sendTo,&sendAddr);
  184.     if (err!=noErr)
  185.         return err;
  186.     
  187.     err = NetSendUDP(gSenderStream,sendAddr,kUDPPort,sendData);
  188.     return err;
  189. }
  190.  
  191.  
  192. /* called to initiate the receiving of a UDP packet */
  193.  
  194. OSErr DoRecvData(DialogPtr theDlg)
  195. {
  196.     OSErr err;
  197.     char incoming[256];
  198.     unsigned short dataLength;
  199.     Handle iHndl;
  200.     Rect iRect;
  201.     short iType;
  202.     
  203.     dataLength = 255;
  204.     err = NetReadUDP(gListenerStream,incoming,&dataLength);
  205.     if (err!=noErr)
  206.         return err;
  207.     
  208.     incoming[dataLength] = '\0';
  209.     CtoPstr(incoming);
  210.     
  211.     GetDItem(theDlg,kRecvData,&iType,&iHndl,&iRect);
  212.     SetIText(iHndl,(StringPtr)incoming);
  213.     
  214.     return noErr;
  215. }
  216.  
  217.  
  218. /*    This is the completion routine used for name-resolver calls.
  219.     It sets the userDataPtr flag to indicate the call has completed.
  220. */
  221.  
  222. pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr)
  223. {
  224. #pragma unused (hInfoPtr)
  225.  
  226.     *userDataPtr = 0xff;
  227. }
  228.  
  229.  
  230. /*    ConvertStringToAddr is a simple call to get a host's IP number, given the name
  231.     of the host.  It copies the fully qualified name back into name, so make sure
  232.     there's space.
  233. */
  234.  
  235. OSErr ConvertStringToAddr(char *name,ip_addr *netNum)
  236. {
  237.     struct hostInfo hInfo;
  238.     OSErr result;
  239.     char done = 0x00;
  240.     extern Boolean gCancel;
  241.  
  242.     if ((result = OpenResolver(nil)) == noErr) {
  243.         result = StrToAddr(name,&hInfo,DNRResultProc,&done);
  244.         if (result == cacheFault)
  245.             while (!done)
  246.                 ; /* wait for cache fault resolver to be called by interrupt */
  247.         CloseResolver();
  248.         if ((hInfo.rtnCode == noErr) || (hInfo.rtnCode == cacheFault)) {
  249.             *netNum = hInfo.addr[0];
  250.             strcpy(name,hInfo.cname);
  251.             name[strlen(name)-1] = '\0';
  252.             return noErr;
  253.         }
  254.     }
  255.     *netNum = 0;
  256.  
  257.     return result;
  258. }
  259.  
  260.  
  261. /* initialize the MacTCP driver */
  262.  
  263. OSErr NetInitUDP(void)
  264. {
  265.     OSErr err;
  266.     
  267.     err = OpenDriver("\p.IPP",&gMTCPDrvr);
  268.     if (err!=noErr)
  269.         return err;
  270.     
  271.     err =  CreateUDPStream(kUDPPort,&gListenerStream,MyASR);
  272.     if (err!=noErr)
  273.         return err;
  274.  
  275.     err = CreateUDPStream(kSenderPort,&gSenderStream,nil);
  276.     if (err!=noErr)
  277.         return err;
  278.  
  279.     err = GetMyIPAddr(&gMyIPAddr);
  280.     return err;
  281. }
  282.  
  283.  
  284. OSErr NetDoneUDP(void)
  285. {
  286.     OSErr err,err2;
  287.     
  288.     err = ReleaseUDPStream(gSenderStream);
  289.     err2 = ReleaseUDPStream(gListenerStream);
  290.     
  291.     if (err==noErr)
  292.         err = err2;
  293.         
  294.     return err;
  295. }
  296.  
  297.  
  298. /* release a UDP Stream */
  299.  
  300. OSErr ReleaseUDPStream(StreamPtr theStream)
  301. {
  302.     UDPiopb udpBlock;
  303.     OSErr err;
  304.  
  305.     udpBlock.ioCRefNum = gMTCPDrvr;
  306.     udpBlock.csCode = UDPRelease;
  307.     udpBlock.udpStream = theStream;
  308.     err = PBControl(&udpBlock,false);
  309.     if (err!=noErr)
  310.         return err;
  311.     
  312.     DisposPtr(udpBlock.csParam.create.rcvBuff);
  313.     return MemError();
  314. }
  315.  
  316.  
  317.  
  318. /* listen for incoming messages */
  319.  
  320. OSErr CreateUDPStream(udp_port udpPort,StreamPtr *theStream,ProcPtr asr)
  321. {
  322.     UDPiopb udpBlock;
  323.     unsigned long bfrSize;
  324.     Ptr buff;
  325.     OSErr err;
  326.     
  327.     bfrSize = 2048;
  328.     buff = NewPtr(bfrSize);
  329.     if (MemError()!=noErr)
  330.         return MemError();
  331.         
  332.     udpBlock.ioCRefNum = gMTCPDrvr;
  333.     udpBlock.csCode = UDPCreate;
  334.     udpBlock.csParam.create.rcvBuff = buff;
  335.     udpBlock.csParam.create.rcvBuffLen = bfrSize;
  336.     udpBlock.csParam.create.localPort = udpPort;
  337.     udpBlock.csParam.create.notifyProc = asr;
  338. #ifdef __SYSEQU__
  339.     udpBlock.csParam.create.userDataPtr = *(long *)CurrentA5;
  340. #else
  341.     udpBlock.csParam.create.userDataPtr = CurrentA5;
  342. #endif
  343.     err = PBControl(&udpBlock,false);
  344.     if (err!=noErr)
  345.         return err;
  346.     
  347.     *theStream = udpBlock.udpStream;
  348. }
  349.  
  350.  
  351. /* send an outgoing message */
  352.  
  353. OSErr NetSendUDP(StreamPtr sendStream,ip_addr sendAddr,udp_port sendPort,char *sendData)
  354. {
  355.     UDPiopb udpBlock;
  356.     EventRecord ev;
  357.     struct wdsEntry theWDS[2];
  358.     OSErr err;
  359.     
  360.     theWDS[0].length = strlen(sendData);
  361.     theWDS[0].ptr = sendData;
  362.     theWDS[1].length = 0;
  363.     theWDS[1].ptr = nil;
  364.  
  365.     udpBlock.udpStream = sendStream;
  366.     udpBlock.ioCompletion = nil;
  367.     udpBlock.ioCRefNum = gMTCPDrvr;
  368.     udpBlock.csCode = UDPWrite;
  369.     udpBlock.csParam.send.reserved = 0;
  370.     udpBlock.csParam.send.remoteHost = sendAddr;
  371.     udpBlock.csParam.send.remotePort = sendPort;
  372.     udpBlock.csParam.send.checkSum = true;
  373.     udpBlock.csParam.send.wdsPtr = (Ptr)theWDS;
  374.     err = PBControl(&udpBlock,true);
  375.     while (udpBlock.ioResult>0)
  376.         EventAvail(everyEvent,&ev);
  377.     return udpBlock.ioResult;
  378. }
  379.  
  380.  
  381. /* receive an incoming packet of data */
  382.  
  383. OSErr NetReadUDP(StreamPtr stream,Ptr data,unsigned short *dataLength)
  384. {
  385.     UDPiopb udpBlock;
  386.     OSErr err;
  387.     
  388.     udpBlock.udpStream = stream;
  389.     udpBlock.ioCRefNum = gMTCPDrvr;
  390.     udpBlock.csCode = UDPRead;
  391.     udpBlock.csParam.receive.timeOut = kTimeout;
  392.     udpBlock.csParam.receive.secondTimeStamp = 0;
  393.     err = PBControl(&udpBlock,false);
  394.     if (err!=noErr)
  395.         return err;
  396.     
  397.     if (udpBlock.csParam.receive.rcvBuffLen==0)
  398.         return noErr;
  399.         
  400.     if (udpBlock.csParam.receive.rcvBuffLen < *dataLength)
  401.         *dataLength = udpBlock.csParam.receive.rcvBuffLen;
  402.     
  403.     BlockMove(udpBlock.csParam.receive.rcvBuff,data,*dataLength);
  404.     
  405.     udpBlock.csCode = UDPBfrReturn;
  406.     err = PBControl(&udpBlock,false);
  407.     return err;
  408. }
  409.  
  410.  
  411.  
  412. /* our async. notification routine */
  413.  
  414. pascal void MyASR(
  415.         StreamPtr udpStream, 
  416.         unsigned short eventCode, 
  417.         Ptr userDataPtr,
  418.         struct ICMPReport *icmpMsg)
  419. {
  420.     long oldA5;
  421.     
  422.     oldA5 = SetA5((long)userDataPtr);
  423.     DoASR(udpStream,eventCode,icmpMsg);
  424.     SetA5(oldA5);
  425. }
  426.  
  427.  
  428. void DoASR(StreamPtr udpStream,unsigned short eventCode,struct ICMPReport *icmpMsg)
  429. {
  430.     if (eventCode==UDPDataArrival && udpStream==gListenerStream) {
  431.         gDataPending = true;
  432.     }
  433. }
  434.  
  435.  
  436. /* return the IP address for this machine */
  437.  
  438. OSErr GetMyIPAddr(ip_addr *addr)
  439. {
  440.     struct GetAddrParamBlock ipBlock;        // may have to change this to IPParamBlock
  441.     OSErr err;
  442.     
  443.     ipBlock.csCode = ipctlGetAddr;
  444.     ipBlock.ioCRefNum = gMTCPDrvr;
  445.     err = PBControl(&ipBlock,false);
  446.     *addr = ipBlock.ourAddress;
  447.  
  448.     return err;
  449. }
  450.  
  451.  
  452. /*-------*/
  453.  
  454. pascal void FrameItem(DialogPtr theDlg,short item)
  455. {
  456.     Handle iHndl;
  457.     Rect iRect;
  458.     short iType;
  459.  
  460.     GetDItem(theDlg,item,&iType,&iHndl,&iRect);
  461.     FrameRect(&iRect);
  462. }
  463.  
  464.  
  465. void NumToIPAddr(ip_addr addr,StringPtr ipStr)
  466. {
  467.     sprintf(ipStr,"%lu.%lu.%lu.%lu",( addr >> 24),
  468.         ((addr & 0x00FFFFFF) >> 16),((addr & 0x0000FFFF) >> 8),
  469.         ( addr & 0x000000FF));
  470.     CtoPstr(ipStr);
  471. }